package com.sun.umbrella.service.bns.role.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.sun.core.enums.BaseBizEnum;
import com.sun.core.enums.BaseErrorEnum;
import com.sun.core.enums.DeletedEnum;
import com.sun.core.enums.YnEnum;
import com.sun.core.ex.BusinessCheckFailException;
import com.sun.core.ex.BusinessProcessFailException;
import com.sun.core.web.page.PageUtil;
import com.sun.star.base.util.BeanUtil;
import com.sun.star.base.util.CollectionUtil;
import com.sun.umbrella.dao.RoleInfoMapper;
import com.sun.umbrella.dao.RoleResRelationMapper;
import com.sun.umbrella.domain.entity.RoleInfoDO;
import com.sun.umbrella.domain.entity.RoleResRelationDO;
import com.sun.umbrella.domain.enums.EnableStateEnum;
import com.sun.umbrella.domain.query.RoleInfoQuery;
import com.sun.umbrella.domain.bo.RoleInfoBO;
import com.sun.umbrella.domain.vo.ChangeRolePermissionVO;
import com.sun.umbrella.domain.vo.RoleSaveOrUpdateVO;
import com.sun.umbrella.service.bns.role.RoleInfoService;
import com.sun.umbrella.session.ContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;


/**
 * @description: 角色信息接口业务层
 * @author: Jay
 * @date: 2018-04-09 16:30
 * @version: V1.0
 */
@Slf4j
@Service
public class RoleInfoServiceImpl implements RoleInfoService {


    @Autowired
    private RoleInfoMapper roleInfoMapper;

    @Autowired
    private RoleResRelationMapper roleResRelationMapper;

    @Autowired
    private ContextHolder contextHolder;

    /**
     * 分页查询角色信息
     *
     * @param roleInfoQuery
     * @param pageable
     * @return
     */
    @Override
    public Page<RoleInfoBO> queryRoleInfoList(RoleInfoQuery roleInfoQuery, Pageable pageable) {
        // 查询总量
        int count = roleInfoMapper.countRoleInfoList(roleInfoQuery);
        if (BaseBizEnum.ZERO.getKey() == count) {
            return PageUtil.newEmptyPage(pageable);
        }
        // 封装分页参数
        PageUtil.fillParam(roleInfoQuery, pageable);
        List<RoleInfoBO> roleInfoBOList = roleInfoMapper.queryRoleInfoList(roleInfoQuery);
        log.info("分页查询角色信息返回值为:{}", JSON.toJSONString(roleInfoBOList));
        if (CollectionUtils.isEmpty(roleInfoBOList)) {
            return PageUtil.newEmptyPage(pageable);
        }
        return PageUtil.newPage(roleInfoBOList, pageable, count);
    }


    /**
     * 新增角色信息
     *
     * @param roleSaveOrUpdateVO
     * @return
     */
    @Transactional(rollbackFor = BusinessProcessFailException.class)
    @Override
    public Boolean saveRoleInfo(RoleSaveOrUpdateVO roleSaveOrUpdateVO) {
        // 参数校验
        this.checkSaveRoleInfoParams(roleSaveOrUpdateVO);
        // 保存
        if (roleInfoMapper.insert(this.fillRoleInfoDO(roleSaveOrUpdateVO)) != BaseBizEnum.FIRST.getKey()) {
            throw new BusinessProcessFailException(BaseErrorEnum.SAVE_ERROR);
        }
        return Boolean.TRUE;
    }


    /**
     * 编辑更新角色信息、启用或者禁用或删除角色
     *
     * @param roleSaveOrUpdateVO
     * @return
     */
    @Transactional(rollbackFor = BusinessProcessFailException.class)
    @Override
    public Boolean updateRoleInfo(RoleSaveOrUpdateVO roleSaveOrUpdateVO) {
        // 参数校验
        this.checkUpdateRoleInfo(roleSaveOrUpdateVO);
        // 更新
        if (roleInfoMapper.updateByIdSelective(this.fillRoleInfoDOForUpdate(roleSaveOrUpdateVO)) != BaseBizEnum.FIRST.getKey()) {
            throw new BusinessProcessFailException(BaseErrorEnum.UPDATE_ERROR);
        }
        return Boolean.TRUE;
    }

    /**
     * 启用 或 禁用
     *
     * @param roleSaveOrUpdateVO
     * @return
     */
    @Transactional(rollbackFor = BusinessProcessFailException.class)
    @Override
    public Boolean enableRoleInfo(RoleSaveOrUpdateVO roleSaveOrUpdateVO) {
        if (roleSaveOrUpdateVO == null) {
            throw new BusinessCheckFailException(BaseErrorEnum.BNS_CHK_ERROR.getCode(), "入参不能为空");
        }
        if (roleSaveOrUpdateVO.getId() == null) {
            throw new BusinessCheckFailException(BaseErrorEnum.BNS_CHK_ERROR.getCode(), "id不能为空");
        }
        Integer enable = roleSaveOrUpdateVO.getRoleEnabled();
        if (enable == null) {
            throw new BusinessCheckFailException(BaseErrorEnum.BNS_CHK_ERROR.getCode(), "roleEnabled不能为空");
        }
        if (enable != EnableStateEnum.ROLE_NOE_ENABLE.getKey() && enable != EnableStateEnum.ROLE_ENABLE.getKey()) {
            throw new BusinessCheckFailException(BaseErrorEnum.BNS_CHK_ERROR.getCode(), "roleEnabled传入值不合法");
        }
        // 更新
        if (roleInfoMapper.updateByIdSelective(this.fillRoleInfoDOForUpdate(roleSaveOrUpdateVO)) != BaseBizEnum.FIRST.getKey()) {
            throw new BusinessProcessFailException(BaseErrorEnum.UPDATE_ERROR);
        }
        return Boolean.TRUE;
    }

    /**
     * 删除角色
     *
     * @param roleSaveOrUpdateVO
     * @return
     */
    @Transactional(rollbackFor = BusinessProcessFailException.class)
    @Override
    public Boolean deleteRoleInfo(RoleSaveOrUpdateVO roleSaveOrUpdateVO) {
        if (roleSaveOrUpdateVO == null) {
            throw new BusinessCheckFailException(BaseErrorEnum.BNS_CHK_ERROR.getCode(), "入参不能为空");
        }
        if (roleSaveOrUpdateVO.getId() == null) {
            throw new BusinessCheckFailException(BaseErrorEnum.BNS_CHK_ERROR.getCode(), "id不能为空");
        }
        roleSaveOrUpdateVO.setIsDeleted(DeletedEnum.YES.getKey());
        // 更新
        if (roleInfoMapper.updateByIdSelective(this.fillRoleInfoDOForUpdate(roleSaveOrUpdateVO)) != BaseBizEnum.FIRST.getKey()) {
            throw new BusinessProcessFailException(BaseErrorEnum.UPDATE_ERROR);
        }
        return Boolean.TRUE;
    }


    /**
     * 分配角色对应的资源权限
     *
     * @param changeRolePermissionVO
     * @return
     */
    @Transactional(rollbackFor = BusinessProcessFailException.class)
    @Override
    public Boolean changeRolePermission(ChangeRolePermissionVO changeRolePermissionVO) {
        if (changeRolePermissionVO == null) {
            throw new BusinessCheckFailException(BaseErrorEnum.BNS_CHK_ERROR.getCode(), "入参不能为空");
        }
        Integer roleId = changeRolePermissionVO.getRoleId();
        if (roleId == null) {
            throw new BusinessCheckFailException(BaseErrorEnum.BNS_CHK_ERROR.getCode(), "roleId不能为空");
        }
        Integer sysId = changeRolePermissionVO.getSysId();
        if (sysId == null) {
            throw new BusinessCheckFailException(BaseErrorEnum.BNS_CHK_ERROR.getCode(), "sysId不能为空");
        }
        // 查询出该角色id对应的数据库中的资源
        List<RoleResRelationDO> roleResRelationDOList = roleResRelationMapper.selectRoleResList(sysId, roleId);
        // 传入的资源id集合，对传入的id集合去重
        List<Integer> originIdList = new ArrayList<>(new TreeSet<>(changeRolePermissionVO.getResDefIdList()));
        // 如果传入值为空 则说明删除了所有
        if (CollectionUtils.isEmpty(originIdList)) {
            return this.first(roleResRelationDOList);
        }
        // 如果传入值不为空,查询得到的数据为空 则全部插入
        if (CollectionUtils.isEmpty(roleResRelationDOList)) {
            return this.secondMethod(originIdList, sysId, roleId);
        }
        // 如果传入值不为空,查询得到的数据也不为空，则传入的部分插入，其他的部分删除
        return this.third(roleResRelationDOList, originIdList, sysId, roleId);
    }


    /*=======================================================privete method=========================================================*/


    /**
     * 如果传入值不为空,查询得到的数据也不为空，则传入的部分插入，其他的部分删除
     *
     * @param roleResRelationDOList
     * @param originIdList
     * @param sysId
     * @param roleId
     * @return
     */
    private Boolean third(List<RoleResRelationDO> roleResRelationDOList, List<Integer> originIdList, Integer sysId, Integer roleId) {
        List<RoleResRelationDO> objAdd = Lists.newArrayList();
        List<Integer> objDelete = Lists.newArrayList();
        // 从数据库中查询出来的结果转map key为resId
        Map<Integer, RoleResRelationDO> dataMap = CollectionUtil.listToMap(roleResRelationDOList, new Function<RoleResRelationDO, Integer>() {
            @Override
            public Integer apply(RoleResRelationDO roleResRelationDO) {
                return roleResRelationDO.getResId();
            }
        });
        // 传入的资源idList转map
        Map<Integer, Integer> idMap = CollectionUtil.listToMap(originIdList, new Function<Integer, Integer>() {
            @Override
            public Integer apply(Integer integer) {
                return integer;
            }
        });
        // 保存需要插入的角色资源记录
        for (Integer originResId : originIdList) {
            // 如果传入的resId不存在，则插入
            if (!dataMap.containsKey(originResId)) {
                objAdd.add(this.fillInsertDO(sysId, roleId, originResId));
            }
        }
        // 删除不需要的资源记录
        for (RoleResRelationDO roleResRelationDO : roleResRelationDOList) {
            // 如果查出来的资源不在传入的资源内，则需要删除存在于数据库中的资源
            if (!idMap.containsKey(roleResRelationDO.getResId())) {
                objDelete.add(roleResRelationDO.getId());
            }
        }
        // 新增记录
        if (objAdd.size() > 0) {
            if (roleResRelationMapper.batchInsert(objAdd) != objAdd.size()) {
                throw new BusinessProcessFailException("分配权限失败", BaseErrorEnum.SAVE_ERROR.getCode());
            }
        }
        if (objDelete.size() > 0) {
            // 删除记录
            if (roleResRelationMapper.deleteRoleResRelation(objDelete, this.getCurrentUserId()) != objDelete.size()) {
                throw new BusinessProcessFailException("分配权限失败", BaseErrorEnum.UPDATE_ERROR.getCode());
            }
        }
        return Boolean.TRUE;
    }


    /**
     * 如果传入值不为空&&查询得到的数据为空 则全部插入
     *
     * @param originIdList
     * @param sysId
     * @param roleId
     * @return
     */
    private Boolean secondMethod(List<Integer> originIdList, Integer sysId, Integer roleId) {
        List<RoleResRelationDO> roleResRelationDOS = Lists.newArrayList();
        for (Integer resId : originIdList) {
            roleResRelationDOS.add(this.fillInsertDO(sysId, roleId, resId));
        }
        if (roleResRelationMapper.batchInsert(roleResRelationDOS) != roleResRelationDOS.size()) {
            throw new BusinessProcessFailException("分配权限失败", BaseErrorEnum.SAVE_ERROR.getCode());
        }
        return Boolean.TRUE;
    }


    /**
     * 如果传入值为空 则说明删除了该角色下所有的资源
     *
     * @param roleResRelationDOList
     * @return
     */
    private Boolean first(List<RoleResRelationDO> roleResRelationDOList) {
        if (CollectionUtils.isEmpty(roleResRelationDOList)) {
            return Boolean.TRUE;
        }
        List<Integer> idList = Lists.newArrayList();
        for (RoleResRelationDO roleResRelationDO : roleResRelationDOList) {
            idList.add(roleResRelationDO.getId());
        }
        // 删除记录
        if (roleResRelationMapper.deleteRoleResRelation(idList, this.getCurrentUserId()) != idList.size()) {
            throw new BusinessProcessFailException("分配权限失败", BaseErrorEnum.UPDATE_ERROR.getCode());
        }
        return Boolean.TRUE;
    }

    /**
     * 填充插入记录
     *
     * @param sysId
     * @param roleId
     * @param resId
     * @return
     */
    private RoleResRelationDO fillInsertDO(Integer sysId, Integer roleId, Integer resId) {
        RoleResRelationDO roleResRelationDO = new RoleResRelationDO();
        roleResRelationDO.setCreator(this.getCurrentUserId());
        roleResRelationDO.setModifier(this.getCurrentUserId());
        roleResRelationDO.setIsDeleted(DeletedEnum.NO.getKey());
        roleResRelationDO.setSysId(sysId);
        roleResRelationDO.setRoleId(roleId);
        roleResRelationDO.setResId(resId);
        return roleResRelationDO;
    }


    /**
     * 参数校验
     *
     * @param roleSaveOrUpdateVO
     */
    private void checkUpdateRoleInfo(RoleSaveOrUpdateVO roleSaveOrUpdateVO) {
        this.checkSaveRoleInfoParams(roleSaveOrUpdateVO);
        if (roleSaveOrUpdateVO.getId() == null) {
            throw new BusinessCheckFailException(BaseErrorEnum.BNS_CHK_ERROR.getCode(), "id不能为空");
        }
    }

    /**
     * DO转换
     *
     * @param roleSaveOrUpdateVO
     * @return
     */
    private RoleInfoDO fillRoleInfoDO(RoleSaveOrUpdateVO roleSaveOrUpdateVO) {
        RoleInfoDO roleInfoDO = new RoleInfoDO();
        BeanUtil.copyProperties(roleSaveOrUpdateVO, roleInfoDO);
        roleInfoDO.setIsDeleted(YnEnum.N.getKey());
        roleInfoDO.setGmtCreate(new Date());
        roleInfoDO.setGmtModified(new Date());
        roleInfoDO.setCreator(this.getCurrentUserId());
        roleInfoDO.setModifier(this.getCurrentUserId());
        roleInfoDO.setRoleEnabled(EnableStateEnum.ROLE_ENABLE.getKey());
        return roleInfoDO;
    }

    /**
     * DO转换
     *
     * @param roleSaveOrUpdateVO
     * @return
     */
    private RoleInfoDO fillRoleInfoDOForUpdate(RoleSaveOrUpdateVO roleSaveOrUpdateVO) {
        RoleInfoDO roleInfoDO = new RoleInfoDO();
        BeanUtil.copyProperties(roleSaveOrUpdateVO, roleInfoDO);
        roleInfoDO.setModifier(this.getCurrentUserId());
        return roleInfoDO;
    }


    /**
     * 新增角色信息的参数校验
     *
     * @param roleSaveOrUpdateVO
     */
    private void checkSaveRoleInfoParams(RoleSaveOrUpdateVO roleSaveOrUpdateVO) {
        if (roleSaveOrUpdateVO == null) {
            throw new BusinessCheckFailException(BaseErrorEnum.BNS_CHK_ERROR.getCode(), "新增角色信息的入参不能为空");
        }
        if (StringUtils.isEmpty(roleSaveOrUpdateVO.getRoleName())) {
            throw new BusinessCheckFailException(BaseErrorEnum.BNS_CHK_ERROR.getCode(), "roleName不能为空");
        }
        if (StringUtils.isEmpty(roleSaveOrUpdateVO.getRoleRemark())) {
            throw new BusinessCheckFailException(BaseErrorEnum.BNS_CHK_ERROR.getCode(), "roleRemark不能为空");
        }
        if (StringUtils.isEmpty(roleSaveOrUpdateVO.getSysId())) {
            throw new BusinessCheckFailException(BaseErrorEnum.BNS_CHK_ERROR.getCode(), "sysId不能为空");
        }
        if (StringUtils.isEmpty(roleSaveOrUpdateVO.getRoleSn())) {
            throw new BusinessCheckFailException(BaseErrorEnum.BNS_CHK_ERROR.getCode(), "roleSn不能为空");
        }
    }


    /**
     * 获取当前登录账号
     *
     * @return
     */
    private Integer getCurrentUserId(){
        Integer userId = contextHolder.getSessionContext().getUserId();
        return userId == null ? 0 : userId;
    }
}
